#pragma once 
#include <cstdlib>
#include <cmath>
#include <cstdio>
#include <iostream>
#include <queue>
#include <ctime>
#include <pthread.h>
#include <unistd.h>

using namespace std;
#define NUM 20

//block queue cp mode
template<typename T>
class BlockQueue
{
  private:
    bool IsFull()
    {
      return cap == q.size(); 
    }

    bool IsEmpty()
    {
      return q.empty();
    }

  public:
    BlockQueue(int _cap = NUM)
      :cap(_cap)
    {
      pthread_mutex_init(&lock, nullptr);
      pthread_cond_init(&full, nullptr);
      pthread_cond_init(&empty, nullptr);
    }

    //producer
    void Push(const T& in)
    {
      pthread_mutex_lock(&lock);
      while(IsFull()){
        //队列满了，需要等待，下面函数作用：1）在特定条件下等待，2）等待的时候，lock锁自动释放
        pthread_cond_wait(&full, &lock); //数据满了，所以需要在满的条件下进行等待，
      }
      q.push(in);
     
      //
     //// if(q.size() >= cap/2){
     ////   cout<<"数据很多，消费吧"<<endl;
     //// }
     // pthread_mutex_unlock(&lock);
     // pthread_cond_signal(&empty); //唤醒消费者
      if(q.size() <= cap/2){
        //cout<<"数据很多，消费吧"<<endl;
        pthread_cond_signal(&empty); //唤醒消费者
      }
      pthread_mutex_unlock(&lock);
    }

    //consumer 
    void Pop(T& out)
    {
      pthread_mutex_lock(&lock);
      while(IsEmpty()){
        //需要等待有数据
        pthread_cond_wait(&empty,&lock);
      }
      out = q.front();
      q.pop();
      if(q.size() >= cap/2){
        //cout<<"空间很多，来消费"<<endl;
        pthread_cond_signal(&full);
      }
      pthread_mutex_unlock(&lock);
      //pthread_cond_signal(&full);
    }

    ~BlockQueue()
    {
      pthread_mutex_destroy(&lock);
      pthread_cond_destroy(&full);
      pthread_cond_destroy(&empty);
    }
  private:
    std::queue<T> q;
    int cap;
    pthread_mutex_t lock;
    pthread_cond_t full;
    pthread_cond_t empty;
};
